/********************************************************
 Name          : led.c
 Author        : Karen Tsarukyan
 Copyright     : Copyright by Antel Systems
 Description   :
**********************************************************/

#include "gpio.h"
#include "led.h"
#include "delay.h"
#include "tc.h"
#include "ADC_api.h"

struct blink Blink;

#define TC_LED_CHANNEL    2
#define TC_IRQ_GROUP        AVR32_TC_IRQ_GROUP
#define TC_IRQ_LED          AVR32_TC_IRQ2

// To specify we have to print a new time
volatile unsigned long long tc2_tick = 0;
unsigned long long state_led_last_time = 0;
unsigned long long state_led_timeout = 0;

unsigned char pwr_flag = 0;
/**************************************************************************************/
#if defined (__GNUC__)
__attribute__((__interrupt__))
#elif defined (__ICCAVR32__)
#pragma handler = EXAMPLE_TC_IRQ_GROUP, 1
__interrupt
#endif
static void TC2_irq(void)
{
	unsigned short clear ;
	double PWIN;
	if((tc2_tick & PERIOD_400_MS) == 0)
	{
		PWIN = (ADC_0_Get() / 38.1) + 0.25;
		if(PWIN < 9)
		{
			if(pwr_flag == 0)
			{
				pwr_flag = 1;
				led_alarm_status_set_color(red);
			}
		}
		else
		{
			if(pwr_flag == 1)
			{
				led_alarm_status_set_color(alarm_status_color);
				pwr_flag = 0;
			}
		}
	}
	if(state_led_timeout > 0)
	{
		if((state_led_timeout + state_led_last_time) < tc2_tick)
		{
			led_state_set_color(color_off);
			state_led_timeout = 0;
		}
	}
  // Increment the ms seconds counter
  tc2_tick++;
  // Clear the interrupt flag. This is a side effect of reading the TC SR.
  //tc_read_sr(TC, TC_CHANNEL);
  clear = (&AVR32_TC)->channel[TC_LED_CHANNEL].sr ;
  // specify that an interrupt has been raised
  switch (Blink.Name[alarm_status]) {
	  case LED_OFF:
                if((tc2_tick & (Blink.alarm_status_blink_period >> 1)) == 0)
                          led_alarm_status_set_color(Blink.alarm_status_old_color);
	        break;
	  case LED_ON:
		  if((tc2_tick & Blink.alarm_status_blink_period) == 0)
			  led_alarm_status_set_color(Blink.alarm_status_color1);
		  else if((tc2_tick & (Blink.alarm_status_blink_period >> 1)) == 0)
	  		  led_alarm_status_set_color(Blink.alarm_status_color2);
		  break;
	  default :
		  return;
  }

  switch (Blink.Name[mode]) {
            case LED_OFF:
                    if((tc2_tick & (Blink.mode_blink_period >> 1)) == 0)
                          led_mode_set_color(Blink.mode_old_color);
              break;
            case LED_ON:
                    if((tc2_tick & Blink.mode_blink_period) == 0)
                            led_mode_set_color(Blink.mode_color1);
                    else if((tc2_tick & (Blink.mode_blink_period >> 1)) == 0)
                            led_mode_set_color(Blink.mode_color2);
                    break;
            default :
                    return;
  }
/*
  switch (Blink.Name[state_grn]) {
              case LED_OFF:
                      if((tc2_tick & Blink.state_grn_blink_period) == 0)
                            gpio_clr_gpio_pin(LED_STATE_GRN);
                      break;
              case LED_ON:
                    if((tc2_tick & Blink.state_blink_period) == 0)
                            gpio_set_gpio_pin(LED_STATE_GRN);
                    else if((tc2_tick & (Blink.state_grn_blink_period >> 1)) == 0)
                            gpio_clr_gpio_pin(LED_STATE_GRN);
                      break;
              default:
                      return;
  }

  switch (Blink.Name[state_red]) {
                case LED_OFF:
                        if((tc2_tick & Blink.state_red_blink_period) == 0)
                              gpio_clr_gpio_pin(LED_STATE_GRN);
                        break;
                case LED_ON:
                      if((tc2_tick & Blink.state_red_blink_period) == 0)
                              gpio_set_gpio_pin(LED_STATE_RED);
                      else if((tc2_tick & (Blink.state_red_blink_period >> 1)) == 0)
                              gpio_clr_gpio_pin(LED_STATE_RED);
                        break;
                default:
                        return;
  }*/
}
/**************************************************************************************/
/**************************************************************************************/
void TC2_init(void)
{
  volatile avr32_tc_t *tc = &AVR32_TC;

  // Options for waveform generation.
  static const tc_waveform_opt_t WAVEFORM_OPT =
  {
    .channel  = TC_LED_CHANNEL,                        // Channel selection.

    .bswtrg   = TC_EVT_EFFECT_NOOP,                // Software trigger effect on TIOB.
    .beevt    = TC_EVT_EFFECT_NOOP,                // External event effect on TIOB.
    .bcpc     = TC_EVT_EFFECT_NOOP,                // RC compare effect on TIOB.
    .bcpb     = TC_EVT_EFFECT_NOOP,                // RB compare effect on TIOB.

    .aswtrg   = TC_EVT_EFFECT_NOOP,                // Software trigger effect on TIOA.
    .aeevt    = TC_EVT_EFFECT_NOOP,                // External event effect on TIOA.
    .acpc     = TC_EVT_EFFECT_NOOP,                // RC compare effect on TIOA: toggle.
    .acpa     = TC_EVT_EFFECT_NOOP,                // RA compare effect on TIOA: toggle (other possibilities are none, set and clear).

    .wavsel   = TC_WAVEFORM_SEL_UP_MODE_RC_TRIGGER,// Waveform selection: Up mode with automatic trigger(reset) on RC compare.
    .enetrg   = FALSE,                             // External event trigger enable.
    .eevt     = 0,                                 // External event selection.
    .eevtedg  = TC_SEL_NO_EDGE,                    // External event edge selection.
    .cpcdis   = FALSE,                             // Counter disable when RC compare.
    .cpcstop  = FALSE,                             // Counter clock stopped with RC compare.

    .burst    = FALSE,                             // Burst signal selection.
    .clki     = FALSE,                             // Clock inversion.
    .tcclks   = TC_CLOCK_SOURCE_TC2                // Internal source clock 3, connected to fPBA / 2.
  };

  static const tc_interrupt_t TC_INTERRUPT =
  {
    .etrgs = 0,
    .ldrbs = 0,
    .ldras = 0,
    .cpcs  = 1,
    .cpbs  = 0,
    .cpas  = 0,
    .lovrs = 0,
    .covfs = 0
  };

  Disable_global_interrupt();

  // The INTC driver has to be used only for GNU GCC for AVR32.
#if defined (__GNUC__)
  // Initialize interrupt vectors.
//  INTC_init_interrupts();

  // Register the RTC interrupt handler to the interrupt controller.
  INTC_register_interrupt(&TC2_irq, TC_IRQ_LED, AVR32_INTC_INT0);
#endif

  // Initialize the timer/counter.
  tc_init_waveform(tc, &WAVEFORM_OPT);         // Initialize the timer/counter waveform.

  // Set the compare triggers.
  // Remember TC counter is 16-bits, so counting second is not possible with fPBA = 12 MHz.
  // We configure it to count ms.
  // We want: (1/(fPBA/8)) * RC = 0.001 s, hence RC = (fPBA/8) / 1000 = 1500 to get an interrupt every 1 ms.
  tc_write_rc(tc, TC_LED_CHANNEL, 37500); // Set RC value.

  tc_configure_interrupts(tc, TC_LED_CHANNEL, &TC_INTERRUPT);

  // Start the timer/counter.
  tc_start(tc, TC_LED_CHANNEL);                    // And start the timer/counter.

  Enable_global_interrupt();
}
/**************************************************************************************/


void led_init(void)
{
	TC2_init();

}
//============================================================================
//----------------------------------------------------------------------------


void led_state_set_color(enum Color c)
{
        Blink.state_current_color = c;
        if(Blink.Name[state] == LED_OFF)
        	Blink.state_old_color = Blink.state_current_color;
        state_led_last_time = tc2_tick;
	switch (c) {
		case color_off:
			gpio_clr_gpio_pin(LED_STATE_GRN);
			gpio_clr_gpio_pin(LED_STATE_RED);
			break;

		case green:
			gpio_set_gpio_pin(LED_STATE_GRN);
			gpio_clr_gpio_pin(LED_STATE_RED);
			break;

		case red:
			gpio_clr_gpio_pin(LED_STATE_GRN);
			gpio_set_gpio_pin(LED_STATE_RED);
			break;

		case yellow:
			gpio_set_gpio_pin(LED_STATE_GRN);
			gpio_set_gpio_pin(LED_STATE_RED);
			break;
	}
}

void led_state_off(unsigned long long timeout)
{
	state_led_timeout = timeout;
}

//----------------------------------------------------------------------------

void led_mode_set_color(enum Color c)
{
        Blink.mode_current_color = c;
        if(Blink.Name[mode] == LED_OFF)
        	Blink.mode_old_color = Blink.mode_current_color;
	switch (c) {
		case color_off:
			gpio_clr_gpio_pin(LED_MODE_GRN);
			gpio_clr_gpio_pin(LED_MODE_RED);
			break;

		case green:
			gpio_set_gpio_pin(LED_MODE_GRN);
			gpio_clr_gpio_pin(LED_MODE_RED);
			break;

		case red:
			gpio_clr_gpio_pin(LED_MODE_GRN);
			gpio_set_gpio_pin(LED_MODE_RED);
			break;

		case yellow:
			gpio_set_gpio_pin(LED_MODE_GRN);
			gpio_set_gpio_pin(LED_MODE_RED);
			break;
	}
}

//----------------------------------------------------------------------------

void led_alarm_status_set_color(enum Color c)
{
        Blink.alarm_status_current_color = c;
        if(Blink.Name[alarm_status] == LED_OFF)
        	Blink.alarm_status_old_color = Blink.alarm_status_current_color;
	switch (c) {
		case color_off:
			gpio_clr_gpio_pin(LED_ALARM_STATUS_GRN);
			gpio_clr_gpio_pin(LED_ALARM_STATUS_RED);
			break;

		case green:
			gpio_set_gpio_pin(LED_ALARM_STATUS_GRN);
			gpio_clr_gpio_pin(LED_ALARM_STATUS_RED);
			break;

		case red:
			gpio_clr_gpio_pin(LED_ALARM_STATUS_GRN);
			gpio_set_gpio_pin(LED_ALARM_STATUS_RED);
			break;

		case yellow:
			gpio_set_gpio_pin(LED_ALARM_STATUS_GRN);
			gpio_set_gpio_pin(LED_ALARM_STATUS_RED);
			break;
	}
}

//----------------------------------------------------------------------------
//============================================================================

//============================================================================
//----------------------------------------------------------------------------

void led_dual_mode_blink_start(enum Color c1, enum Color c2, unsigned short blink_period)
{
	Blink.mode_color1 = c1;
	Blink.mode_color2 = c2;
	Blink.Name[mode] = LED_ON;
	Blink.mode_blink_period = blink_period;
	Blink.mode_old_color = Blink.mode_current_color;
}

void led_dual_mode_blink_end(void)
{
        Blink.Name[mode] = LED_OFF;
}

void led_mode_grn_blink_start(unsigned short blink_period)
{
        Blink.Name[alarm_status_grn] = LED_ON;
        Blink.alarm_status_grn_blink_period = blink_period;
        Blink.alarm_status_old_color = Blink.alarm_status_current_color;
}

void led_mode_grn_blink_end(void)
{
        Blink.Name[alarm_status_grn] = LED_OFF;
}

void led_mode_red_blink_start(unsigned short blink_period)
{
        Blink.Name[alarm_status_red] = LED_ON;
        Blink.alarm_status_red_blink_period = blink_period;
        Blink.alarm_status_old_color = Blink.alarm_status_current_color;
}

void led_mode_red_blink_end(void)
{
        Blink.Name[alarm_status_red] = LED_OFF;
}


//----------------------------------------------------------------------------

void led_dual_alarm_status_blink_start(enum Color c1, enum Color c2, unsigned short blink_period)
{
	Blink.alarm_status_color1 = c1;
	Blink.alarm_status_color2 = c2;
	Blink.Name[alarm_status] = LED_ON;
	Blink.alarm_status_blink_period = blink_period;
	Blink.alarm_status_old_color = Blink.alarm_status_current_color;
}

void led_dual_alarm_status_blink_end(void)
{
        Blink.Name[alarm_status] = LED_OFF;
}

void led_alarm_status_grn_blink_start(char blink_period)
{
        Blink.Name[alarm_status_grn] = LED_ON;
        Blink.alarm_status_grn_blink_period = blink_period;
        Blink.alarm_status_old_color = Blink.alarm_status_current_color;
}

void led_alarm_status_grn_blink_end(void)
{
        Blink.Name[alarm_status_grn] = LED_OFF;
}

void led_alarm_status_red_blink_start(unsigned short blink_period)
{
        Blink.Name[alarm_status_red] = LED_ON;
        Blink.alarm_status_red_blink_period = blink_period;
        Blink.alarm_status_old_color = Blink.alarm_status_current_color;
}

void led_alarm_status_red_blink_end(void)
{
        Blink.Name[alarm_status_red] = LED_OFF;
}


//----------------------------------------------------------------------------

void led_dual_state_blink_start(enum Color c1, enum Color c2, unsigned short blink_period)
{
	Blink.state_color1 = c1;
	Blink.state_color2 = c2;
	Blink.Name[state] = LED_ON;
	Blink.state_blink_period = blink_period;
	Blink.state_old_color = Blink.state_current_color;
}

void led_dual_state_blink_end(void)
{
        Blink.Name[state] = LED_OFF;
}

void led_state_grn_blink_start(unsigned short blink_period)
{
        Blink.Name[state_grn] = LED_ON;
        Blink.state_grn_blink_period = blink_period;
        Blink.state_old_color = Blink.state_current_color;
}

void led_state_grn_blink_end(void)
{
        Blink.Name[state_grn] = LED_OFF;
}

void led_state_red_blink_start(unsigned short blink_period)
{
        Blink.Name[state_red] = LED_ON;
        Blink.state_red_blink_period = blink_period;
        Blink.state_old_color = Blink.state_current_color;
}

void led_state_red_blink_end(void)
{
        Blink.Name[state_red] = LED_OFF;
}


//----------------------------------------------------------------------------
//============================================================================



